﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using NHibernate;
using VegetableStore.Providers;
using VegetableStore.Util;
using VegetableStore.Domains;
using System.Globalization;
using NHibernate.Criterion;

namespace VegetableStore.Controllers
{
    public class ProductController : Controller
    {
        private ISession nhibernateSession;
        private enum ORDERBY_TYPE
        {
            DATE, PRICE, DISCOUNT_RATE
        }

        public ProductController()
        {
            nhibernateSession = SessionProvider.Instance.GetSession();
        }

        [AllowAnonymous]
        [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
        public JsonResult GetAllProductCategory(string token)
        {
            try
            {
                if (token == null) return Json(new { result = "FAILURE", msg = "token이 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);
                if (!AuthUtil.IsAuthorized(token)) return Json(new { result = "FAILURE", msg = "인증되지 않은 접근입니다." }, JsonRequestBehavior.AllowGet);
                IList<Productcategory> productCategoryList = nhibernateSession.CreateCriteria<Productcategory>().List<Productcategory>();
                return Json(new { result = "SUCCESS", data = productCategoryList }, JsonRequestBehavior.AllowGet);
            }
            catch (Exception e)
            {
                if (e.InnerException == null) return Json(new { result = "FAILURE", msg = e.Message }, JsonRequestBehavior.AllowGet);
                else return Json(new { result = "FAILURE", msg = e.InnerException.Message }, JsonRequestBehavior.AllowGet);
            }
        }

        [AllowAnonymous]
        [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
        public JsonResult SearchStandardProductListByCategoryId(string token, int? productCategoryId)
        {
            try
            {
                if (productCategoryId == null) return Json(new { result = "FAILURE", msg = "productCategoryId가 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);
                if (token == null) return Json(new { result = "FAILURE", msg = "token이 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);
                if (!AuthUtil.IsAuthorized(token)) return Json(new { result = "FAILURE", msg = "인증되지 않은 접근입니다." }, JsonRequestBehavior.AllowGet);

                IList<Standardproduct> standardProductList = nhibernateSession.QueryOver<Standardproduct>()
                    .JoinQueryOver<Productcategory>(standardProduct => standardProduct.Productcategory)
                    .Where(productCategory => productCategory.Id == productCategoryId)
                    .List<Standardproduct>();
                return Json(new { result = "SUCCESS", data = standardProductList }, JsonRequestBehavior.AllowGet);
            }
            catch (Exception e)
            {
                if (e.InnerException == null) return Json(new { result = "FAILURE", msg = e.Message }, JsonRequestBehavior.AllowGet);
                else return Json(new { result = "FAILURE", msg = e.InnerException.Message }, JsonRequestBehavior.AllowGet);
            }
        }

        [AllowAnonymous]
        [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
        public JsonResult SearchStandardProductListByName(string token, string name)
        {
            try
            {
                if (token == null) return Json(new { result = "FAILURE", msg = "token이 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);
                if (!AuthUtil.IsAuthorized(token)) return Json(new { result = "FAILURE", msg = "인증되지 않은 접근입니다." }, JsonRequestBehavior.AllowGet);
                IList<Standardproduct> standardProductList = nhibernateSession.QueryOver<Standardproduct>()
                    .WhereRestrictionOn(c=>c.Name).IsLike("%"+name+"%")
                    .List<Standardproduct>();                
                return Json(new { result = "SUCCESS", data = standardProductList }, JsonRequestBehavior.AllowGet);
            }
            catch (Exception e)
            {
                if (e.InnerException == null) return Json(new { result = "FAILURE", msg = e.Message }, JsonRequestBehavior.AllowGet);
                else return Json(new { result = "FAILURE", msg = e.InnerException.Message }, JsonRequestBehavior.AllowGet);
            }
        }

        [AllowAnonymous]
        [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
        public JsonResult GetStandardProduct(string token, int? id)
        {
            try
            {
                if (id == null) return Json(new { result = "FAILURE", msg = "id가 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);
                if (token == null) return Json(new { result = "FAILURE", msg = "token이 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);
                if (!AuthUtil.IsAuthorized(token)) return Json(new { result = "FAILURE", msg = "인증되지 않은 접근입니다." }, JsonRequestBehavior.AllowGet);
                Standardproduct standardProduct = nhibernateSession.Get<Standardproduct>(id);
                return Json(new { result = "SUCCESS", data = standardProduct }, JsonRequestBehavior.AllowGet);
            }
            catch (Exception e)
            {
                if (e.InnerException == null) return Json(new { result = "FAILURE", msg = e.Message }, JsonRequestBehavior.AllowGet);
                else return Json(new { result = "FAILURE", msg = e.InnerException.Message }, JsonRequestBehavior.AllowGet);
            }
        }

        [AllowAnonymous]
        [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
        public JsonResult InsertProduct(string token, int? storeId, int? standardProductId, int? imageId, string name,
            float? unitQuantity, int? price, int? quantity, string originPlace, string receivingDate, string comment)
        {
            try
            {
                if (storeId == null) return Json(new { result = "FAILURE", msg = "storeId가 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);
                if (standardProductId == null) return Json(new { result = "FAILURE", msg = "standardProductId가 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);
                if (name == null) return Json(new { result = "FAILURE", msg = "name이 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);
                if (unitQuantity == null) return Json(new { result = "FAILURE", msg = "unitQuantity가 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);
                if (price == null) return Json(new { result = "FAILURE", msg = "price가 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);
                if (receivingDate == null) return Json(new { result = "FAILURE", msg = "receivingDate가 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);
                if (quantity == null) return Json(new { result = "FAILURE", msg = "quantity가 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);
                if (token == null) return Json(new { result = "FAILURE", msg = "token이 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);
                if (!AuthUtil.IsAuthorized(token)) return Json(new { result = "FAILURE", msg = "인증되지 않은 접근입니다." }, JsonRequestBehavior.AllowGet);
                try
                {
                    DateTime.ParseExact(receivingDate, "yyyyMMdd", CultureInfo.InvariantCulture); 
                }
                catch (FormatException e)
                {
                    return Json(new { result = "FAILURE", msg = "receivingDate타입이 yyyyMMdd가 아닙니다." }, JsonRequestBehavior.AllowGet);
                }
                Product product = new Product
                {
                    Store = nhibernateSession.Load<Store>(storeId),
                    Standardproduct = nhibernateSession.Load<Standardproduct>(standardProductId),
                    Image = nhibernateSession.Load<Image>(imageId),
                    Name = name,
                    UnitQuantity = (float)unitQuantity,
                    Price = (int)price,
                    Quantity = (int)quantity,
                    OriginPlace = originPlace,
                    ReceivingDate = receivingDate,
                    Comments = comment,
                    RegistrationDate = DateTime.Now.ToString("yyyyMMddHHmmss"),
                    UseYN = true
                };
                using (var tx = nhibernateSession.BeginTransaction())
                {
                    try
                    {
                        nhibernateSession.Save(product);
                        nhibernateSession.Flush();
                        tx.Commit();
                    }
                    catch (Exception te)
                    {
                        tx.Rollback();
                        SessionProvider.Instance.CloseSession();
                        throw te;
                    }
                }
                return Json(new { result = "SUCCESS", data = new { productId = product.Id } }, JsonRequestBehavior.AllowGet);
            }
            catch (Exception e)
            {
                if (e.InnerException == null) return Json(new { result = "FAILURE", msg = e.Message }, JsonRequestBehavior.AllowGet);
                else return Json(new { result = "FAILURE", msg = e.InnerException.Message }, JsonRequestBehavior.AllowGet);
            }
        }


        [AllowAnonymous]
        [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
        public JsonResult GetProduct(string token, int? id)
        {
            try
            {
                if (id == null) return Json(new { result = "FAILURE", msg = "id가 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);
                if (token == null) return Json(new { result = "FAILURE", msg = "token이 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);
                if (!AuthUtil.IsAuthorized(token)) return Json(new { result = "FAILURE", msg = "인증되지 않은 접근입니다." }, JsonRequestBehavior.AllowGet);
                Product product = nhibernateSession.Get<Product>(id);
                return Json(new { result = "SUCCESS", data = product }, JsonRequestBehavior.AllowGet);
            }
            catch (Exception e)
            {
                if (e.InnerException == null) return Json(new { result = "FAILURE", msg = e.Message }, JsonRequestBehavior.AllowGet);
                else return Json(new { result = "FAILURE", msg = e.InnerException.Message }, JsonRequestBehavior.AllowGet);
            }
        }

        [AllowAnonymous]
        [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
        public JsonResult DeleteProduct(string token, int? id)
        {
            try
            {
                if (id == null) return Json(new { result = "FAILURE", msg = "id가 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);
                if (token == null) return Json(new { result = "FAILURE", msg = "token이 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);
                if (!AuthUtil.IsAuthorized(token)) return Json(new { result = "FAILURE", msg = "인증되지 않은 접근입니다." }, JsonRequestBehavior.AllowGet);
                Product product = nhibernateSession.Get<Product>(id);
                product.UseYN = false;
                nhibernateSession.Update(product);
                nhibernateSession.Flush();
                return Json(new { result = "SUCCESS"}, JsonRequestBehavior.AllowGet);
            }
            catch (Exception e)
            {
                if (e.InnerException == null) return Json(new { result = "FAILURE", msg = e.Message }, JsonRequestBehavior.AllowGet);
                else return Json(new { result = "FAILURE", msg = e.InnerException.Message }, JsonRequestBehavior.AllowGet);
            }
        }

        [AllowAnonymous]
        [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
        public JsonResult SearchProductListByCategoryId(string token, int? categoryId)
        {
            try
            {
                if (token == null) return Json(new { result = "FAILURE", msg = "token이 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);
                if (!AuthUtil.IsAuthorized(token)) return Json(new { result = "FAILURE", msg = "인증되지 않은 접근입니다." }, JsonRequestBehavior.AllowGet);

                Product productAlias = null;
                Store storeAlias = null;
                Market marketAlias = null;
                Standardproduct standardProductAlias = null;
                Productcategory productCategoryAlias = null;

                Users user = nhibernateSession.CreateQuery("from Users where token = :token")
                    .SetString("token", token)
                    .UniqueResult<Users>();

                IQueryOver<Product, Product> queryOver = nhibernateSession.QueryOver<Product>(() => productAlias)
                 .JoinAlias(() => productAlias.Store, () => storeAlias)
                 .JoinAlias(() => storeAlias.Market, () => marketAlias)
                 .JoinAlias(() => productAlias.Standardproduct, () => standardProductAlias)
                 .JoinAlias(() => standardProductAlias.Productcategory, () => productCategoryAlias);

                queryOver = queryOver.WhereRestrictionOn(() => marketAlias.Id).IsLike(user.FavoriteMarket.Id)
                    .Where(x => x.UseYN == true);
                
                if (categoryId != null) queryOver = queryOver.WhereRestrictionOn(() => productCategoryAlias.Id).IsLike(categoryId);
                IList<Product> productList = queryOver.List<Product>();

                return Json(new { result = "SUCCESS", data = productList }, JsonRequestBehavior.AllowGet);
            }
            catch (Exception e)
            {
                if (e.InnerException == null) return Json(new { result = "FAILURE", msg = e.Message }, JsonRequestBehavior.AllowGet);
                else return Json(new { result = "FAILURE", msg = e.InnerException.Message }, JsonRequestBehavior.AllowGet);
            }
        }

        [AllowAnonymous]
        [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
        public JsonResult SearchProductListOrderByDate(string token, int? categoryId, int? standardProductId, string name, int? pageSize, int? pageNum)
        {
            try
            {
                if (token == null) return Json(new { result = "FAILURE", msg = "token이 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);
                if (!AuthUtil.IsAuthorized(token)) return Json(new { result = "FAILURE", msg = "인증되지 않은 접근입니다." }, JsonRequestBehavior.AllowGet);

                IList<Product> productList = SearchProductList(token, categoryId, standardProductId, name, pageSize, pageNum, ORDERBY_TYPE.DATE);
                return Json(new { result = "SUCCESS", data = productList }, JsonRequestBehavior.AllowGet);
            }
            catch (Exception e)
            {
                if (e.InnerException == null) return Json(new { result = "FAILURE", msg = e.Message }, JsonRequestBehavior.AllowGet);
                else return Json(new { result = "FAILURE", msg = e.InnerException.Message }, JsonRequestBehavior.AllowGet);
            }
        }

        [AllowAnonymous]
        [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
        public JsonResult SearchProductListOrderByPrice(string token, int? categoryId, int? standardProductId, string name, int? pageSize, int? pageNum)
        {
            try
            {
                if (token == null) return Json(new { result = "FAILURE", msg = "token이 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);
                if (!AuthUtil.IsAuthorized(token)) return Json(new { result = "FAILURE", msg = "인증되지 않은 접근입니다." }, JsonRequestBehavior.AllowGet);

                IList<Product> productList = SearchProductList(token, categoryId, standardProductId, name, pageSize, pageNum, ORDERBY_TYPE.PRICE);
                return Json(new { result = "SUCCESS", data = productList }, JsonRequestBehavior.AllowGet);
            }
            catch (Exception e)
            {
                if (e.InnerException == null) return Json(new { result = "FAILURE", msg = e.Message }, JsonRequestBehavior.AllowGet);
                else return Json(new { result = "FAILURE", msg = e.InnerException.Message }, JsonRequestBehavior.AllowGet);
            }
        }

        //[AllowAnonymous]
        //[AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
        //public JsonResult SearchProductListOrderByDiscountRate(string token, int? categoryId, int? standardProductId, string name, int? pageSize, int? pageNum)
        //{
        //    try
        //    {
        //        if (token == null) return Json(new { result = "FAILURE", msg = "token이 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);
        //        if (!AuthUtil.IsAuthorized(token)) return Json(new { result = "FAILURE", msg = "인증되지 않은 접근입니다." }, JsonRequestBehavior.AllowGet);

        //        IList<Product> productList = SearchProductList(token, categoryId, name, pageSize, pageNum, ORDERBY_TYPE.DISCOUNT_RATE);
        //        return Json(new { result = "SUCCESS", data = productList }, JsonRequestBehavior.AllowGet);
        //    }
        //    catch (Exception e)
        //    {
        //        return Json(new { result = "FAILURE", msg = e.Message }, JsonRequestBehavior.AllowGet);
        //    }
        //}

        private IList<Product> SearchProductList(string token, int? categoryId, int? standardProductId, string name, int? pageSize, int? pageNum, ORDERBY_TYPE orderbyType)
        {
            Product productAlias = null;
            Store storeAlias = null;
            Market marketAlias = null;
            Standardproduct standardProductAlias = null;
            Productcategory productCategoryAlias = null;

            Users user = nhibernateSession.CreateQuery("from Users where token = :token")
                .SetString("token", token)
                .UniqueResult<Users>();

            IQueryOver<Product, Product> queryOver = nhibernateSession.QueryOver<Product>(() => productAlias)
                .JoinAlias(() => productAlias.Store, () => storeAlias)
                .JoinAlias(() => storeAlias.Market, () => marketAlias)
                .JoinAlias(() => productAlias.Standardproduct, () => standardProductAlias)
                .JoinAlias(() => standardProductAlias.Productcategory, () => productCategoryAlias)
                .WhereRestrictionOn(() => marketAlias.Id).IsLike(user.FavoriteMarket.Id)
                .Where(x => x.UseYN == true);
            

            if (name != null)
            {
                queryOver = queryOver.WhereRestrictionOn(c => c.Name).IsLike("%" + name + "%");
            }

            if (standardProductId != null)
            {
                queryOver = queryOver.WhereRestrictionOn(() => standardProductAlias.Id).IsLike(standardProductId);
            }

            if (categoryId != null)
            {
                queryOver = queryOver.WhereRestrictionOn(() => productCategoryAlias.Id).IsLike(categoryId);
            }

            switch (orderbyType)
            {
                case ORDERBY_TYPE.DATE: 
                    queryOver = queryOver.OrderBy(x => x.RegistrationDate).Desc;
                    break;
                case ORDERBY_TYPE.PRICE:
                    queryOver = queryOver.OrderBy(x => x.Price).Asc;
                    break;
                //case ORDERBY_TYPE.DISCOUNT_RATE:
                //    //
                //    break;
                default:
                    queryOver = queryOver.OrderBy(x => x.RegistrationDate).Desc;
                    break;
            }            

            if (pageSize != null && pageNum != null)
            {
                int pageSize1 = pageSize ?? 0;
                int pageNum1 = pageNum ?? 0;
                queryOver.Skip(pageNum1 * pageSize1).Take(pageSize1);
            }

            return queryOver.List<Product>();
        }

        [AllowAnonymous]
        [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
        public JsonResult GetMyStoresProductList(string token)
        {
            try
            {
                if (token == null) return Json(new { result = "FAILURE", msg = "token이 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);
                if (!AuthUtil.IsAuthorized(token)) return Json(new { result = "FAILURE", msg = "인증되지 않은 접근입니다." }, JsonRequestBehavior.AllowGet);

                Product productAlias = null;

                Users user = nhibernateSession.QueryOver<Users>()
                    .Where(x => x.Token == token)
                    .List()
                    .FirstOrDefault();
                
                IList<Usersstore> usersStoreList = nhibernateSession.QueryOver<Usersstore>()
                    .Where(x => x.Users == user)
                    .List();
                IList<Store> storeList = new List<Store>();
                foreach (Usersstore usersStore in usersStoreList)
                {
                    storeList.Add(usersStore.Store);
                }                
                IList<Product> productList = nhibernateSession.QueryOver<Product>(() => productAlias)
                    .WhereRestrictionOn(() => productAlias.Store).IsIn(storeList.ToArray<Store>())
                    .Where(x => x.UseYN == true)
                    .List();
                    
                return Json(new { result = "SUCCESS", data = productList }, JsonRequestBehavior.AllowGet);
            }
            catch (Exception e)
            {
                if (e.InnerException == null) return Json(new { result = "FAILURE", msg = e.Message }, JsonRequestBehavior.AllowGet);
                else return Json(new { result = "FAILURE", msg = e.InnerException.Message }, JsonRequestBehavior.AllowGet);
            }
        }

        [AllowAnonymous]
        [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
        public JsonResult ModifyProduct(string token, int? productId, int? imageId, string name,
            float? unitQuantity, int? price, int? quantity, string originPlace, string receivingDate, string comment)
        {
            try
            {
                if (productId == null) return Json(new { result = "FAILURE", msg = "productId가 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);
                if (token == null) return Json(new { result = "FAILURE", msg = "token이 입력되어야 합니다." }, JsonRequestBehavior.AllowGet);
                if (!AuthUtil.IsAuthorized(token)) return Json(new { result = "FAILURE", msg = "인증되지 않은 접근입니다." }, JsonRequestBehavior.AllowGet);
                
                Product product = nhibernateSession.Get<Product>(productId);
                if (product == null) return Json(new { result = "FAILURE", msg = "id가 " + productId + "인 상품이 없습니다." }, JsonRequestBehavior.AllowGet);
                if (imageId != null)
                {
                    Image image = nhibernateSession.Get<Image>(imageId);
                    if (image == null) return Json(new { result = "FAILURE", msg = "id가 " + imageId + "인 이미지가 없습니다." }, JsonRequestBehavior.AllowGet);
                    product.Image = image;
                }
                if (name != null) product.Name = name;
                if (unitQuantity != null) product.UnitQuantity = (float)unitQuantity;
                if (price != null) product.Price = (int)price;
                if (quantity != null) product.Quantity = (int)quantity;
                if (originPlace != null) product.OriginPlace = originPlace;
                if (receivingDate != null)
                {
                    try
                    {
                        DateTime.ParseExact(receivingDate, "yyyyMMdd", CultureInfo.InvariantCulture);
                    }
                    catch (FormatException e)
                    {
                        return Json(new { result = "FAILURE", msg = "receivingDate타입이 yyyyMMdd가 아닙니다." }, JsonRequestBehavior.AllowGet);
                    }
                    product.ReceivingDate = receivingDate;
                }
                if (comment != null) product.Comments = comment;
                product.RegistrationDate = DateTime.Now.ToString("yyyyMMddHHmmss");
                
                using (var tx = nhibernateSession.BeginTransaction())
                {
                    try
                    {
                        nhibernateSession.Update(product);
                        nhibernateSession.Flush();
                        tx.Commit();
                    }
                    catch (Exception te)
                    {
                        tx.Rollback();
                        SessionProvider.Instance.CloseSession();
                        throw te;
                    }
                }
                return Json(new { result = "SUCCESS", data = product }, JsonRequestBehavior.AllowGet);
            }
            catch (Exception e)
            {
                if (e.InnerException == null) return Json(new { result = "FAILURE", msg = e.Message }, JsonRequestBehavior.AllowGet);
                else return Json(new { result = "FAILURE", msg = e.InnerException.Message }, JsonRequestBehavior.AllowGet);
            }
        }
    }    
}
